package org.kernelab.basis.test.linenumbertablepane;

import javax.swing.*;
import javax.swing.table.*;
import java.awt.*;
import java.beans.*;

final public class LineNumberTablePane extends JScrollPane
{
	private class NumberTableColumnModel extends DefaultTableColumnModel
	{
		/**
		 * 
		 */
		private static final long	serialVersionUID	= 4827060404670113143L;

		private NumberTableColumnModel()
		{
			rowHeaderColumn.setIdentifier(ROW_HEADER_IDENTIFIER);
			rowHeaderColumn.setHeaderValue(ROW_HEADER_VALUE);

			TableCellRenderer renderer = new RowHeaderCellRenderer();

			rowHeaderColumn.setCellRenderer(renderer);
			rowHeaderColumn.setHeaderRenderer(renderer);
			addColumn(rowHeaderColumn);
		}

		public int getColumnCount()
		{
			return 1;
		}
	}

	private class NumberTableModel extends DefaultTableModel
	{
		/**
		 * 
		 */
		private static final long	serialVersionUID	= -8586377926214431137L;

		public Class<?> getColumnClass(int columnIndex)
		{
			return columnIndex == 0 ? Integer.class : null;
		}

		public int getColumnCount()
		{
			return 1;
		}

		public String getColumnName(int column)
		{
			return column == 0 ? ROW_HEADER_COLUMN_NAME : "";
		}

		public Object getValueAt(int rowIndex, int columnIndex)
		{
			return columnIndex == 0 ? rowIndex + 1 : null;
		}

		public boolean isCellEditable(int rowIndex, int columnIndex)
		{
			return false;
		}
	}

	private class RowHeaderCellRenderer implements TableCellRenderer
	{
		public Component getTableCellRendererComponent(JTable table, Object value,
				boolean isSelected, boolean hasFocus, int row, int column)
		{
			JLabel label = new JLabel() {
				/**
				 * 
				 */
				private static final long	serialVersionUID	= -2866560422385859677L;

				public Insets getInsets()
				{
					return new Insets(0, 0, 0, 0);
				}
			};

			label.setHorizontalAlignment(SwingConstants.RIGHT);
			if (column == 0) {
				label.setText(value.toString());
				label.setOpaque(true);
				label.setBackground(Color.BLACK);
				label.setForeground(Color.YELLOW);
			}
			return label;
		}
	}

	/**
	 * 
	 */
	private static final long	serialVersionUID				= 5743321320668933486L;

	private static final int	DEFAULT_MIN_ROW_HEADER_WIDTH	= 30;

	private static final String	ROW_HEADER_IDENTIFIER			= "lineNumberColumn";

	private static final String	ROW_HEADER_COLUMN_NAME			= "lineNumberRowColumn";

	private static final String	ROW_HEADER_VALUE				= "行号";

	private JTable				primaryTable					= new JTable();

	private JTable				numberTable						= new JTable();

	private TableColumn			rowHeaderColumn					= new TableColumn(0);

	private DefaultTableModel	rowHeaderTableModel				= new NumberTableModel();

	public LineNumberTablePane(final JTable primaryTableComponent,
			final JTable numberTableComponent)
	{
		super(JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
				JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
		primaryTable = primaryTableComponent;
		primaryTable.setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
		numberTable = numberTableComponent;
		numberTable.setModel(rowHeaderTableModel);
		numberTable.setColumnModel(new NumberTableColumnModel());

		checkPropertyListeners();
		notifyRowsChanged();
	}

	private void adjustRowHeaderHeight()
	{
		setViewportView(primaryTable);
		setRowHeaderView(numberTable);
		int h = this.getVerticalScrollBar().getSize().height;
		getRowHeader().setPreferredSize(new Dimension(DEFAULT_MIN_ROW_HEADER_WIDTH, h));
	}

	private void checkPropertyListeners()
	{
		primaryTable.addPropertyChangeListener(new PropertyChangeListener() {
			public void propertyChange(PropertyChangeEvent evt)
			{
				if (evt.getPropertyName().equals("rowHeight")) {
					Integer h = (Integer) evt.getNewValue();
					numberTable.setRowHeight(h);
					adjustRowHeaderHeight();
				}
			}
		});
	}

	public JTable getPrimaryTable()
	{
		return primaryTable;
	}

	public JTable getRowHeaderTable()
	{
		return numberTable;
	}

	public void notifyRowsChanged()
	{
		while (rowHeaderTableModel.getRowCount() > 0)
			rowHeaderTableModel.removeRow(0);
		for (int i = 0, j = primaryTable.getRowCount(); i < j; i++)
			rowHeaderTableModel.addRow(new Integer[] { i + 1 });
		adjustRowHeaderHeight();
	}

	public void scrollRowToVisible(int row)
	{
		int rowMargin = primaryTable.getRowMargin();

		int y = 0, w = 0;
		for (int i = 0; i < row; i++)
			y += primaryTable.getRowHeight(i) + rowMargin;

		TableColumnModel columnModel = primaryTable.getColumnModel();
		for (int i = 0, j = columnModel.getColumnCount(); i < j; i++)
			w += columnModel.getColumn(i).getWidth();

		primaryTable.scrollRectToVisible(new Rectangle(0, y, w, primaryTable
				.getRowHeight(row)));
	}
}
